import logging
import threading
import inspect

_logger_init_lock = threading.Lock()

# CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
_log_level_map = {
    'CRITICAL' : logging.CRITICAL,
    'ERROR' : logging.ERROR,
    'WARNING' : logging.WARNING,
    'INFO' : logging.INFO,
    'DEBUG' : logging.DEBUG,
    'NOTEST' : logging.NOTSET
}

class Singleton(object):
    """
    Description: Singleton class implement
    """
    def __new__(cls, *args, **kw):
        _logger_init_lock.acquire()
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        _logger_init_lock.release()
        return cls._instance

class LoggerSingleton(Singleton):
    """
    Description: A logger with singleton implement
    """
    logger_file_name_set = set()
    logger_file_name_dict = {}
    cur_logger = None

    def __init__(self, log_file_handler_name, log_level):
        """
        Parameters:
            log_file_handler_name:  the log output file name
            log_level:  the level of the logger
        Description: Logger initialize
        """
        if log_file_handler_name in self.logger_file_name_set:
            self.cur_logger = logging.getLogger(log_file_handler_name)
        else:
            logger = logging.getLogger(log_file_handler_name)
            hdlr = logging.FileHandler(filename = log_file_handler_name)
            formater = logging.Formatter('%(levelname)s [%(asctime)s] %(message)s')
            hdlr.setFormatter(formater)
            logger.addHandler(hdlr)
            logger.setLevel(log_level)
            self.logger_file_name_set.add(log_file_handler_name)
            self.cur_logger = logger
            self.logger_file_name_dict[logger] = log_file_handler_name

    def debug(self, msg):
        self.cur_logger.debug(msg)

    def info(self, msg):
        self.cur_logger.info(msg)

    def warn(self, msg):
        self.cur_logger.warn(msg)

    def error(self, msg):
        self.cur_logger.error(msg)

def global_var_init(log_file_name = '', log_level = ''):
    """
    Parameters:
        log_file_name:  the output file of the msg
        log_level:  log level
    Description: Initialize global log
    """
    global DEFAULT_LOG_FILE, DEFAULT_LOG_DEBUG_LEVEL, _cur_log_file_name_dict, _cur_log_level_dict
    _cur_log_file_name_dict = {}
    _cur_log_level_dict = {}
    if log_file_name != '':
        DEFAULT_LOG_FILE = log_file_name
    else:
        DEFAULT_LOG_FILE = '/var/log/wmclod_finacial.log'

    if log_level != '' and log_level in _log_level_map:
        DEFAULT_LOG_DEBUG_LEVEL = log_level
    else:
        DEFAULT_LOG_DEBUG_LEVEL = 'DEBUG'

def init_global_log(log_file_name = '', log_level = ''):
    """
    Parameters:
        log_file_name:  the output file of the msg
        log_level:  log level
    Description: Initialize global log
    """
    global_var_init(log_file_name, log_level)

    # print('default log file %s, level %s' % (DEFAULT_LOG_FILE, DEFAULT_LOG_DEBUG_LEVEL))

def init_log(log_file_name = '', log_level = ''):
    """
    Parameters:
        log_file_name:  the output file of the msg
        log_level:  log level
    Description: Initialize log for the file which call this function.
    """
    global_var_init()
    call_stack = inspect.stack()
    _cur_log_file_name_dict[call_stack[1][1]] = DEFAULT_LOG_FILE if log_file_name == '' else log_file_name
    _cur_log_level_dict[call_stack[1][1]] = logging.DEBUG if log_level == '' or log_level not in _log_level_map else _log_level_map[log_level]

def get_logger_singleton(log_file_name = '', log_level = ''):
    """
    Parameters:
        msg:    message
        log_file_name:  the output file of the msg
        log_level:  the level of the log
    Description: Log of info level
    """
    _cur_log_file_name = DEFAULT_LOG_FILE if log_file_name == '' else log_file_name
    _cur_log_level = logging.DEBUG if log_level == '' or log_level not in _log_level_map else _log_level_map[log_level]

    call_stack = inspect.stack()
    # print('get logger in %s' % (call_stack[2][1]))
    caller_file = call_stack[2][1]
    if caller_file in _cur_log_file_name_dict:
        _cur_log_file_name = _cur_log_file_name_dict[caller_file]
    if caller_file in _cur_log_level_dict:
        _cur_log_level = _cur_log_level_dict[caller_file]
    # print('cur log file %s level %s' % (_cur_log_file_name, _cur_log_level))
    logsingleton = LoggerSingleton(_cur_log_file_name, _cur_log_level)
    return logsingleton

def info(msg, log_file_name = ''):
    """
    Parameters:
        msg:    message
        log_file_name:  the output file of the msg
    Description: Log of info level
    """
    logsingleton = get_logger_singleton(log_file_name)
    logsingleton.info(msg)

def warn(msg, log_file_name = ''):
    """
    Parameters:
        msg:    message
        log_file_name:  the output file of the msg
    Description: Log of warning level
    """
    logsingleton = get_logger_singleton(log_file_name)
    logsingleton.warn(msg)

def debug(msg, log_file_name = ''):
    """
    Parameters:
        msg:    message
        log_file_name:  the output file of the msg
    Description: Log of debug level
    """
    logsingleton = get_logger_singleton(log_file_name)
    logsingleton.debug(msg)

def error(msg, log_file_name = ''):
    """
    Parameters:
        msg:    message
        log_file_name:  the output file of the msg
    Description: Log of error level
    """
    logsingleton = get_logger_singleton(log_file_name)
    logsingleton.error(msg)
